#ifndef mbObj
#include "bsp.h"
#include "pincfg.h"
#include "os_obj.h"
#include "mbapp.h"
#include "com_def.h"
#include "common.h"

#define mbRxEnable()
#define mbTxEnable()
mb_obj_type mbObj;
#define mbPORT USART0
#define mbURT_IRQn USART0_IRQn
static void mb_cb_set(void)
{
}
static void mb_port_hal_cfg(void) {}
#endif

static void mb_cb_set(void);
static void mbObjInit(mb_mode_type mbMode);
static void mbPortTx1Rx0Enable(uint8_t mode);
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity);
static void mbDataSend(void);
static void mb_port_hal_cfg(void);
static void (*mb_byte_send)(uint8_t dat);

/***************************************************************************** 
* @brief UART OPT
*****************************************************************************/
// 数据收发
#define UART_SEND_DAT(dat) USART_TDATA(mbPORT) = dat
#define UART_RCV_DAT() USART_RDATA(mbPORT)

// 缓冲状态
#define UART_RX_NE_ST() ((USART_STAT(mbPORT) & USART_STAT_RBNE) != 0) //rx not empty
#define UART_TX_NF_ST() (0 != (USART_STAT(mbPORT) & USART_STAT_TBE))  //tx not full
#define UART_TX_TC_ST() (USART_STAT(mbPORT) & (USART_STAT_TC))
#define UART_TX_TC_CLR() USART_INTC(mbPORT) = USART_INTC_TCC

// 接收控制
#define UART_RX_EN() USART_CTL0(mbPORT) |= USART_CTL0_UEN | USART_CTL0_REN
#define UART_RX_INT_EN() USART_CTL0(mbPORT) |= USART_CTL0_UEN | USART_CTL0_REN | USART_CTL0_RBNEIE
#define UART_RX_INT_DIS() USART_CTL0(mbPORT) &= ~(USART_CTL0_REN | USART_CTL0_RBNEIE)

// 发送控制
#define UART_TX_EN() USART_CTL0(mbPORT) |= USART_CTL0_UEN | USART_CTL0_TEN
#define UART_TX_INT_EN() USART_CTL0(mbPORT) |= USART_CTL0_UEN | USART_CTL0_TBEIE | USART_CTL0_TEN
#define UART_TX_INT_DIS() USART_CTL0(mbPORT) &= ~(USART_CTL0_TBEIE | USART_CTL0_TCIE)

// 错误标志及清除
#define UART_RX_ERR_FLAG (USART_STAT_PERR | USART_STAT_FERR)
#define UART_RX_ERR_CLR() USART_INTC(mbPORT) = USART_INTC_PEC | USART_INTC_FEC

/***************************************************************************** 
* @brief mb_byte_send
* @param   dat
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mb_rtu_byte_send(uint8_t dat)
{
	UART_TX_TC_CLR();
	USART_TDATA(mbPORT) = dat;
}

static void mb_asc_byte_send(uint8_t dat)
{
	UART_TX_TC_CLR();
	USART_TDATA(mbPORT) = dat;
}

/***************************************************************************** 
* @brief UART interrupt routine.     
* @param   none
* @return  none
*****************************************************************************/
void mbISR()
{
	volatile uint32_t IntSt;
	volatile uint8_t Data;

	mbObj.timeout_cnt = 0;

	IntSt = USART_STAT(mbPORT);

	if (IntSt & USART_STAT_RBNE)
	{
		Data = USART_RDATA(mbPORT);

		if ((IntSt & UART_RX_ERR_FLAG) != 0)
		{
			if (mbObj.rcv_cnt >= 1)
			{
				mbObj.err_st.bits.hal = 1;
			}
			UART_RX_ERR_CLR();
		}

		mb_data_rcv(&mbObj, Data);
	}
	else if ((mbObj.snd_size <= mbObj.snd_cnt) && (IntSt & USART_STAT_TC))
	{
		mb_send_end(&mbObj);
		mbPortTx1Rx0Enable(0);
		UART_TX_TC_CLR();
	}
	else if (IntSt & USART_STAT_TBE)
	{
		if (mb_data_send(&mbObj, mb_byte_send, 1))
		{
			cset_mask(USART_CTL0(mbPORT), USART_CTL0_TBEIE, USART_CTL0_TCIE);
		}
	}
	else
	{
	}
}

/***************************************************************************** 
* @brief   	com modle init .
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity)
{
	uint32_t dat_bits;
	uint32_t stop_bits;
	uint32_t parity;

	mb_port_hal_cfg();

	mbObjInit(mbMode);

	mb_byte_send = mb_rtu_byte_send;

	if (mbMode == MB_RTU_MASTER || mbMode == MB_RTU_SLAVE)
	{
		// rtu mode
		if (MB_PAR_NONE == eParity)
		{
			dat_bits = USART_WL_8BIT;
			stop_bits = USART_STB_2BIT;
			parity = USART_PM_NONE;
		}
		else if (MB_PAR_NONE_1S == eParity)
		{
			dat_bits = USART_WL_8BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_NONE;
		}
		else if (MB_PAR_ODD == eParity)
		{
			dat_bits = USART_WL_9BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_ODD;
		}
		else
		{
			dat_bits = USART_WL_9BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_EVEN;
		}

		mbObj.run_st.bits.rtu_mode = 1;
	}
	else
	{
		mb_byte_send = mb_asc_byte_send;

		// asc mode
		if (MB_PAR_NONE == eParity)
		{
			dat_bits = USART_WL_8BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_NONE;
		}
		else if (MB_PAR_NONE_1S == eParity)
		{
			dat_bits = USART_WL_8BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_NONE;
		}
		else if (MB_PAR_ODD == eParity)
		{
			dat_bits = USART_WL_8BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_ODD;
		}
		else
		{
			dat_bits = USART_WL_8BIT;
			stop_bits = USART_STB_1BIT;
			parity = USART_PM_EVEN;
		}

		mbObj.run_st.bits.rtu_mode = 0;
	}

	// rtu timer
	if (mbObj.run_st.bits.rtu_mode == 0)
	{
		mbObj.rtu_timer_sv = 240;
		mbObj.timeout_set = 500;
	}
	else
	{
		if (ulBaudRate > 19200)
		{
			mbObj.rtu_timer_sv = 3;
		}
		else
		{
			mbObj.rtu_timer_sv = (com_timer_cal(ulBaudRate, (35 * 11 + 9) / 10, 300, 12000) + 99) / 100;
		}
	}

	usart_baudrate_set(mbPORT, ulBaudRate);
	usart_word_length_set(mbPORT, dat_bits);
	usart_stop_bit_set(mbPORT, stop_bits);
	usart_parity_config(mbPORT, parity);
	usart_enable(mbPORT);

	nvic_irq_set(mbURT_IRQn, 0x02, 1);

	mbPortTx1Rx0Enable(0);
}

/***************************************************************************** 
*
* @brief   Uart En or Dis.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mbPortTx1Rx0Enable(uint8_t mode)
{
	volatile uint8_t u8Temp;

	if (0 == mode)
	{
		mbRxEnable();

		UART_TX_INT_DIS();
		UART_RX_EN();

		u8Temp = UART_RCV_DAT();
		while (UART_RX_NE_ST())
		{
			u8Temp = UART_RCV_DAT();
			__DSB();
		}

		UART_RX_INT_EN();
	}
	else
	{
		mbTxEnable();

		UART_RX_INT_DIS();

		UART_TX_EN();

		UART_SEND_DAT(mbObj.adu_buff[mbObj.snd_cnt++]);

		UART_TX_INT_EN();
	}
}

/***************************************************************************** 
*
* @brief   Send data.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbDataSend(void)
{
	mbTxEnable();

	UART_RX_INT_DIS();

	UART_TX_EN();

	UART_SEND_DAT(mbObj.adu_buff[mbObj.snd_cnt++]);

	UART_TX_INT_EN();
}

/***************************************************************************** 
*
* @brief   mb object init.
*             
* @param   none
*
* @return  TURE
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbObjInit(mb_mode_type mbMode)
{
	mb_obj_init(&mbObj);
	mbObj.adu_send = &mbDataSend;

	mb_cb_set();

	mbObj.master.err_cnt = 0;

	//SLAVE FUNCTION INIT
	if (MB_RTU_MASTER == mbMode || mbMode == MB_ASCII_MASTER)
	{
		mbObj.run_st.bits.master_mode = 1;
	}
	else
	{
		mbObj.run_st.bits.master_mode = 0;
	}
}

/***************************************************************************** 
* @brief   sim_mbport_keep    
* @param   none
* @return  none
*****************************************************************************/
#ifndef mbObj
void sim_mbport_keep(void)
{
	mb_port_Init(MB_RTU_SLAVE, 9600, MB_PAR_NONE);
}
#endif